// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: hgpark

#include <boost/utility/string_view.hpp>
#include <gflags/gflags.h>
#include <spdlog/async.h>
#include <spdlog/details/fmt_helper.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/spdlog.h>

#include <ctime>
#include <sstream>

#include "coin2/base/time.h"
#include "coin2/strategy/rmm_strat/rmm_strategy.h"

DEFINE_string(driver, "", "driver config");
DEFINE_string(config, "", "strategy config");
DEFINE_int32(strat_num, 0, "strategy number");
DEFINE_bool(is_sim, false, "simulation mode");
DEFINE_string(sim_result_filepath, "", "sim result filepath");
DEFINE_int64(sim_start_ts, 0, "start timestamp for simulation");

class nms_filter_flag : public spdlog::custom_flag_formatter {
public:
  void format(const spdlog::details::log_msg &msg, const std::tm &, spdlog::memory_buf_t &dest) override {
    boost::string_view msg_(msg.payload.data(), msg.payload.size());
    if (msg_.find("NOT_MANAGED_SYMBOL") != boost::string_view::npos ||
        msg_.find("add_from_order_proto") != boost::string_view::npos) {
      return;
    }
    spdlog::details::fmt_helper::append_string_view(msg.payload, dest);
  }

  std::unique_ptr<custom_flag_formatter> clone() const override {
    return spdlog::details::make_unique<nms_filter_flag>();
  }
};


int main(int argc, char* argv[]) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);

  /*
  auto current_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
  std::tm tm = *std::localtime(&current_time);
  std::stringstream log_filename_suffix;
  log_filename_suffix << std::put_time(&tm, "%Y%m%d_%H%M%S");
  */
  auto path = std::experimental::filesystem::path(FLAGS_driver);
  coin2::app::DriverConfig app_config;
  app_config.MergeFrom(coin2::base::config::DriverConfigFromJson(path));
  std::string strat_name = (*app_config.mutable_strategy()).strategy_name();
  google::InitGoogleLogging(strat_name.c_str());

  (*app_config.mutable_strategy()).set_strategy_name(strat_name);

  // split log files every 1 GiB / at most 5 files
  auto rotating_async_logger = spdlog::rotating_logger_mt<spdlog::async_factory>(
      "async_file_logger",
      fmt::format("{}/data/rmm_log/{}", std::getenv("HOME"), strat_name),
      1048576 * 1024,
      4);
  spdlog::set_default_logger(rotating_async_logger);
  // flush every 5 sec
  spdlog::flush_every(std::chrono::seconds(5));
  auto formatter = std::make_unique<spdlog::pattern_formatter>();
  formatter->add_flag<nms_filter_flag>('*').set_pattern("%Y%m%d.%H%M%S.%f [%s:%!:%#] %*");
  spdlog::set_formatter(std::move(formatter));
  // spdlog::set_pattern("%Y%m%d.%H%M%S.%f [%s:%!:%#] %v");

  SPDLOG_INFO("App config: {}", app_config.DebugString());

  coin2::strategy::rmm_strat::RmmStrategy strategy(
      FLAGS_config,
      FLAGS_strat_num,
      FLAGS_is_sim,
      FLAGS_sim_result_filepath,
      FLAGS_sim_start_ts);
  coin2::app::Driver driver(app_config, &strategy);
  strategy.SetMainIoc(driver.live_executor()->MainIoc());
  driver.RegisterCleanupHandler();
  driver.Run();
  return 0;
}
